package org.apache.ocean.main.server;

import java.io.IOException;
import java.net.URL;
import java.text.ParseException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.Weight;
import org.apache.ocean.main.IndexDocuments;
import org.apache.ocean.main.Snapshot;
import org.apache.ocean.main.TransactionSystem;
import org.apache.ocean.main.Index.IndexSnapshot;
import org.apache.ocean.main.TransactionSystem.Category;
import org.apache.ocean.main.name.NameClient;
import org.apache.ocean.main.replication.Replication;
import org.apache.ocean.main.replication.Replication.NameInterface;
import org.apache.ocean.main.search.CachedDocumentFrequencySearcher;
import org.apache.ocean.main.search.DocumentSearch;
import org.apache.ocean.main.search.SnapshotSearch;
import org.apache.ocean.main.search.TermFrequencies;
import org.apache.ocean.main.search.DocumentSearch.DocumentFieldSelector;
import org.apache.ocean.main.search.DocumentSearch.DocumentQuery;
import org.apache.ocean.main.search.DocumentSearch.DocumentResult;
import org.apache.ocean.main.search.Search.Result;
import org.apache.ocean.main.search.Search.ScoreDoc;
import org.apache.ocean.main.search.Search.SearchQuery;
import org.apache.ocean.main.util.Service;

public class TransactionServer implements Service {
	public static Logger log = Logger.getLogger(TransactionServer.class.getName());
	private TransactionSystem transactionSystem;
	private Replication replication;
	private NameClient nameClient;
	private String cell;
	private String serviceStatus;
	private String id;
	private URL url;
	private ExecutorService searchThreadPool;

	public TransactionServer() {

	}
  
	public ExecutorService getSearchThreadPool() {
		return searchThreadPool;
	}
	
	public String getCell() {
		return cell;
	}
	
	public IndexDocuments getGetDocuments(String categoryName, Long snapshotid, List<Long> docIds, SortedSet<String> fields) throws ParseException, IOException {
		Category category = transactionSystem.getCategory(categoryName);
		Snapshot snapshot = category.getSnapshots().get(snapshotid);
		DocumentFieldSelector fieldSelector = new DocumentFieldSelector(fields);
		return snapshot.getDocuments(docIds, fieldSelector);
	}
	
	public TermFrequencies getTermFrequencies(Query rewrittenQuery, Snapshot snapshot) throws IOException {
		Set<Term> terms = new HashSet<Term>();
		rewrittenQuery.extractTerms(terms);
		int maxDoc = snapshot.getMaxDoc();
		TermFrequencies termFrequencies = new TermFrequencies(maxDoc, snapshot.getSnapshotId(), snapshot.getCategory().getCategoryIndexSchema());
		for (IndexSnapshot indexSnapshot : snapshot.getIndexSnapshots()) {
			for (Term term : terms) {
			  int frequency = indexSnapshot.getIndexReader().docFreq(term);
			  termFrequencies.add(term, frequency);
			}
		}
		return termFrequencies;
	}
	
	public Weight getWeight(Query original, TermFrequencies termFrequencies, Snapshot snapshot) throws IOException {
		Query rewrittenQuery = rewriteQuery(original, snapshot);
		CachedDocumentFrequencySearcher cachedDocumentFrequencySearcher = new CachedDocumentFrequencySearcher(termFrequencies, Similarity.getDefault());
		return rewrittenQuery.weight(cachedDocumentFrequencySearcher);
	}
	
	public Query rewriteQuery(Query original, Snapshot snapshot) throws IOException {
		Collection<IndexSnapshot> indexSnapshots = snapshot.getIndexSnapshots();
		Query[] queries = new Query[indexSnapshots.size()];
		int i = 0;
    for (IndexSnapshot indexSnapshot : indexSnapshots) {
    	IndexSearcher indexSearcher = new IndexSearcher(indexSnapshot.getIndexReader());
      queries[i] = indexSearcher.rewrite(original);
      i++;
    }
    return queries[0].combine(queries); 
	}
	
	public Weight getWeight(Query query, Snapshot snapshot) throws Exception {
		Query rewrittenQuery = rewriteQuery(query, snapshot);
		TermFrequencies termFrequencies = getTermFrequencies(rewrittenQuery, snapshot);
		CachedDocumentFrequencySearcher cachedDocumentFrequencySearcher = new CachedDocumentFrequencySearcher(termFrequencies, Similarity.getDefault());
		return rewrittenQuery.weight(cachedDocumentFrequencySearcher);
	}
	
	public DocumentResult search(DocumentQuery documentQuery, Snapshot snapshot) throws Exception {
		DocumentSearch documentSearch = new DocumentSearch(documentQuery, snapshot, searchThreadPool);
		DocumentResult documentResult = documentSearch.call();
		return documentResult;
	}
	
	public URL getUrl() {
		return url;
	}
	
	public String getId() {
		return id;
	}
	
	public String getServiceStatus() {
		return serviceStatus;
	}

	public void updateCellNodes(String cellID, List<Replication.Node> nodes) throws Exception {

	}

	public class NameHandler implements NameInterface {
		public void notifyChange() {
			try {
				String operatingRole = replication.getOperatingRole();
				if (StringUtils.equals("master", operatingRole)) {
					List<Replication.Node> nodes = replication.getLeases().getNodes();
					
				}
			} catch (Throwable throwable) {
				log.log(Level.SEVERE, "", throwable);
			}
		}
	}

	public void start() {
		serviceStatus = Service.STARTING;
		searchThreadPool = Executors.newFixedThreadPool(30);
		serviceStatus = Service.STARTED;
	}

	public void stop() {
		serviceStatus = Service.STOPPING;

		serviceStatus = Service.STOPPED;
	}
}
